// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.

// Author: Shuo Chen (chenshuo at chenshuo dot com)

#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#include "muduo/net/TimerQueue.h"

#include "muduo/base/Logging.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/Timer.h"
#include "muduo/net/TimerId.h"

#include <sys/timerfd.h>
#include <unistd.h>

namespace muduo {
namespace net {
namespace detail {

/**
 * 创建一个定时器文件描述符
 *
 * 本函数通过系统调用timerfd_create创建一个定时器，并配置为非阻塞和关闭执行模式。
 * 定时器基于单调时钟，确保了时间的准确性不受系统时钟调整的影响。
 *
 * @return 返回创建的定时器文件描述符。如果创建失败，将通过日志记录错误信息，并退出程序。
 */
int createTimerfd()
{
    int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
    if (timerfd < 0) {
        LOG_SYSFATAL << "Failed in timerfd_create";
    }
    return timerfd;
}

/**
 * 计算从现在到指定时间戳的间隔。
 *
 * 该函数通过比较当前时间戳和指定时间戳之间的微秒差值，来计算从现在到指定时间的间隔。
 * 如果计算得到的差值小于100微秒，则将其调整为100微秒，以确保最小延迟。
 *
 * @param when 指定的时间戳，表示一个未来的时间点。
 * @return 返回一个timespec结构体，其中包含了从现在到指定时间的秒和纳秒间隔。
 */
struct timespec howMuchTimeFromNow(Timestamp when)
{
    // 计算从现在到指定时间的微秒差值
    int64_t microseconds =
        when.microSecondsSinceEpoch() - Timestamp::now().microSecondsSinceEpoch();

    // 确保最小延迟时间为100微秒
    if (microseconds < 100) {
        microseconds = 100;
    }

    // 根据微秒差值，计算timespec结构体的秒和纳秒部分
    struct timespec ts;
    ts.tv_sec  = static_cast<time_t>(microseconds / Timestamp::kMicroSecondsPerSecond);
    ts.tv_nsec = static_cast<long>((microseconds % Timestamp::kMicroSecondsPerSecond) * 1000);

    return ts;
}

/**
 * 读取timerfd的到期事件计数。
 *
 * 本函数负责从timerfd读取到期的事件次数。当timerfd有事件发生时（即计时器到期），
 * 通过调用此函数来获取到期的次数。这在处理计时器队列时非常关键，因为它允许
 * 程序知道有多少计时器已经到期，从而可以相应地处理这些计时器。
 *
 * @param timerfd Timer文件描述符，用于读取计时器到期事件。
 * @param now 当前时间戳，用于记录日志。
 */
void readTimerfd(int timerfd, Timestamp now)
{
    uint64_t howmany;  // 用于存储读取的到期事件次数。

    // 尝试从timerfd读取到期事件的次数。
    ssize_t n = ::read(timerfd, &howmany, sizeof howmany);

    // 记录读取到的到期事件次数的日志。
    LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();

    // 检查读取的字节数是否与预期相符。
    if (n != sizeof howmany) {
        // 如果读取的字节数不正确，记录错误日志。
        LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
    }
}

// /**
//  * 读取timerfd的到期事件计数。
//  * @param timerfd Timer文件描述符，用于读取到期事件。
//  * @param now 当前时间戳，用于记录日志。
//  */
// void readTimerfd(int timerfd, Timestamp now)
// {
//     uint64_t howmany;  // 用于存储读取的到期事件次数。
//     // 从timerfd中读取到期事件的次数。
//     ssize_t n = ::read(timerfd, &howmany, sizeof howmany);
//     LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString();
//     if (n != sizeof howmany) {
//         LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8";
//     }
// }

/**
 * 重置计时器。
 *
 * 该函数用于重新设置给定的timerfd的到期时间。它首先计算出从现在到目标到期时间的间隔，
 * 然后使用这个间隔来更新timerfd的定时器设置。如果更新操作失败，函数将记录一个系统错误。
 *
 * @param timerfd 需要重置的计时器文件描述符。
 * @param expiration 目标到期时间。
 */
void resetTimerfd(int timerfd, Timestamp expiration)
{
    // wake up loop by timerfd_settime()
    struct itimerspec newValue;
    struct itimerspec oldValue;
    memZero(&newValue, sizeof newValue);
    memZero(&oldValue, sizeof oldValue);
    newValue.it_value = howMuchTimeFromNow(expiration);

    // 设置定时器的触发时间，并获取之前的设置信息。参数0表示使用默认的定时器精度。
    int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue);
    if (ret) {
        LOG_SYSERR << "timerfd_settime()";
    }
}

}  // namespace detail
}  // namespace net
}  // namespace muduo

using namespace muduo;
using namespace muduo::net;
using namespace muduo::net::detail;

TimerQueue::TimerQueue(EventLoop* loop)
    : loop_(loop)
    , timerfd_(createTimerfd())
    , timerfdChannel_(loop, timerfd_)
    , timers_()
    , callingExpiredTimers_(false)
{
    timerfdChannel_.setReadCallback(std::bind(&TimerQueue::handleRead, this));
    // we are always reading the timerfd, we disarm it with timerfd_settime.
    timerfdChannel_.enableReading();
}

TimerQueue::~TimerQueue()
{
    timerfdChannel_.disableAll();
    timerfdChannel_.remove();
    ::close(timerfd_);
    // do not remove channel, since we're in EventLoop::dtor();
    for (const Entry& timer : timers_) {
        delete timer.second;
    }
}

TimerId TimerQueue::addTimer(TimerCallback cb, Timestamp when, double interval)
{
    auto* timer = new Timer(std::move(cb), when, interval);
    loop_->runInLoop(std::bind(&TimerQueue::addTimerInLoop, this, timer));
    return TimerId(timer, timer->sequence());
}

void TimerQueue::cancel(TimerId timerId)
{
    loop_->runInLoop(std::bind(&TimerQueue::cancelInLoop, this, timerId));
}

void TimerQueue::addTimerInLoop(Timer* timer)
{
    loop_->assertInLoopThread();
    bool earliestChanged = insert(timer);
    printf("earliestChanged = %d\n", earliestChanged);
    if (earliestChanged) {
        resetTimerfd(timerfd_, timer->expiration());
    }
}

void TimerQueue::cancelInLoop(TimerId timerId)
{
    loop_->assertInLoopThread();
    assert(timers_.size() == activeTimers_.size());
    ActiveTimer timer(timerId.timer_, timerId.sequence_);
    auto        it = activeTimers_.find(timer);
    if (it != activeTimers_.end()) {
        size_t n = timers_.erase(Entry(it->first->expiration(), it->first));
        assert(n == 1);
        (void)n;
        delete it->first;  // FIXME: no delete please
        activeTimers_.erase(it);
    } else if (callingExpiredTimers_) {
        cancelingTimers_.insert(timer);
    }
    assert(timers_.size() == activeTimers_.size());
}

void TimerQueue::handleRead()
{
    // 关注最早的定时器，但可能有多个定时器超时时间一样
    loop_->assertInLoopThread();
    Timestamp now(Timestamp::now());
    readTimerfd(timerfd_, now);

    std::vector<Entry> expired = this->getExpired(now);

    callingExpiredTimers_ = true;
    cancelingTimers_.clear();
    // safe to callback outside critical section
    for (const Entry& it : expired) {
        it.second->run();
    }
    callingExpiredTimers_ = false;

    reset(expired, now);
}

std::vector<TimerQueue::Entry> TimerQueue::getExpired(Timestamp now)
{
    assert(timers_.size() == activeTimers_.size());
    std::vector<Entry> expired;
    Entry              sentry(now, reinterpret_cast<Timer*>(UINTPTR_MAX));
    auto               end = timers_.lower_bound(sentry);
    assert(end == timers_.end() || now < end->first);
    std::copy(timers_.begin(), end, back_inserter(expired));
    timers_.erase(timers_.begin(), end);

    for (const Entry& it : expired) {
        ActiveTimer timer(it.second, it.second->sequence());
        size_t      n = activeTimers_.erase(timer);
        assert(n == 1);
        (void)n;
    }

    assert(timers_.size() == activeTimers_.size());
    return expired;
}

void TimerQueue::reset(const std::vector<Entry>& expired, Timestamp now)
{
    Timestamp nextExpire;

    for (const Entry& it : expired) {
        ActiveTimer timer(it.second, it.second->sequence());
        if (it.second->repeat() && cancelingTimers_.find(timer) == cancelingTimers_.end()) {
            it.second->restart(now);
            insert(it.second);
        } else {
            // FIXME move to a free list
            delete it.second;  // FIXME: no delete please
        }
    }

    if (!timers_.empty()) {
        nextExpire = timers_.begin()->second->expiration();
    }

    if (nextExpire.valid()) {
        resetTimerfd(timerfd_, nextExpire);
    }
}

/**
 * 将一个新的定时器插入到定时器队列中。
 *
 * @param timer 要插入的定时器指针。
 * @return 如果插入操作导致了最早触发时间的改变，则返回true；否则返回false。
 *
 * 此函数确保在定时器循环线程中调用，以维护线程安全。
 * 它首先检查定时器队列是否为空，或者新定时器的触发时间是否早于当前最早触发的定时器。
 * 如果是，它将标记最早触发时间改变。然后，它将新定时器插入到排序的定时器列表中，
 * 并将其也插入到活动定时器集合中。最后，它再次确认定时器和活动定时器的数量相等，
 * 以确保数据结构的一致性。
 */
bool TimerQueue::insert(Timer* timer)
{
    // 确保操作在定时器循环线程中执行
    loop_->assertInLoopThread();

    // 确保定时器队列和活动定时器集合的大小一致
    assert(timers_.size() == activeTimers_.size());

    // 标记最早触发时间是否改变
    bool earliestChanged = false;
    // 获取新定时器的触发时间
    Timestamp when = timer->expiration();
    // 遍历定时器列表查找最早触发时间
    auto it = timers_.begin();
    // 如果定时器列表为空或新定时器的触发时间早于最早触发时间，则最早触发时间改变
    if (it == timers_.end() || when < it->first) {
        earliestChanged = true;
    }

    // 插入新定时器到定时器列表，并确认插入成功
    {
        std::pair<TimerList::iterator, bool> result = timers_.insert(Entry(when, timer));
        assert(result.second);
        (void)result;
    }

    // 插入新定时器到活动定时器集合，并确认插入成功
    {
        std::pair<ActiveTimerSet::iterator, bool> result =
            activeTimers_.insert(ActiveTimer(timer, timer->sequence()));
        assert(result.second);
        (void)result;
    }

    assert(timers_.size() == activeTimers_.size());
    return earliestChanged;
}
